home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / oper_sys / presto / prest_04.lha / src / unix / process.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-08-08  |  9.9 KB  |  472 lines

  1. /*
  2.  * process.c:
  3.  *
  4.  *    Implementation of process class.
  5.  *
  6.  *    Main routine p_wait is where each scheduling thread lives.
  7.  *    
  8.  *
  9.  * Last modified:        12/21/87
  10.  * by:                bnb
  11.  * reason:            add these comments
  12.  *
  13.  */
  14.  
  15.  
  16. #define _PROCESS_C
  17.  
  18.  
  19. #include <sys/types.h>
  20. #include <signal.h>
  21. #include <osfcn.h>
  22. #include "presto.h"
  23.  
  24. Process staticproc;
  25. Process *sysproc = &staticproc;
  26.  
  27. private_t Process *thisproc = 0;    // always ME!
  28.  
  29. //
  30. // ptag proc constructor is useful for getting a handle on the root
  31. // process.  Since we weren't around when he got forked, we kluge
  32. // with this.
  33. //
  34. Process::Process(int ptag, int id)
  35. {
  36.     int p_continue();        // signal handler
  37.  
  38.     if (ptag != P_ROOT /* || no root exists */ )    {
  39.         error("Invalid attempt to flag root Process\n");
  40.     }
  41.     p_id = id;
  42.     p_ppid = getppid();
  43.     p_pid = getpid();
  44.     p_name = "ROOT";
  45.     p_flags = P_ROOT;
  46.     p_state = S_RUN;        // obviously
  47.     p_request = 0;
  48.     p_thread = 0;
  49.     p_schedthread = thisthread;
  50.     thisproc = this;
  51.     signal(SIGCONT, p_continue);
  52. }
  53.  
  54.  
  55. Process::Process(char* name, int id, int delayedfork)
  56. {
  57.     p_name = name;
  58.     p_request = 0;
  59.     p_flags = 0;
  60.     p_id = id;
  61.     p_schedthread = p_thread = 0;
  62.     if  (!delayedfork)
  63.         p_fork();
  64.     else
  65.         p_state = S_DELAYEDFORK;
  66.     return;
  67. }
  68.  
  69. //
  70. // Constructor for staticproc (sysproc).
  71. //
  72. Process::Process()
  73. {
  74. #if (sun && THREAD_HAS_INTERRUPTIBLE_FIELD)
  75.     p_interruptible = 0;
  76. #endif
  77. #ifdef vax 
  78.     p_interruptible = 0;
  79. #endif vax
  80.     p_name = "sysproc";
  81. }
  82.  
  83. //
  84. // Delay the fork until after the return of the constructor.  Derived
  85. // classes will need to take advantage of this to ensure that the
  86. // virtual table in the derived class is properly initalized.  Use
  87. // for a derived class is:
  88. //
  89. //    DerivedProcess::DerivedProcess(args) : (name, id,  S_DELAYEDFORK)
  90. //    {
  91. //        initialize derived part
  92. //        Process::p_fork();        
  93. //        /* only parent returns to here.  Child never does */
  94. //    }
  95. //
  96. // Must be careful to use private stack when forking into child; else
  97. // parent and child can race on the shared stack (leads to strange
  98. // core dumps -- hard to diagnose).  This should be cleaned up; use of
  99. // asm-functions may help.
  100.  
  101. void
  102. Process::p_fork()
  103. {
  104.     int pid;
  105.     int spinonfork = 1;        // hold child until done
  106.     static private_t int private_stack[256];
  107.  
  108.     extern int _rtmp;
  109.  
  110. #ifdef sun
  111.     _rtmp = (int) &private_stack[sizeof(private_stack) / sizeof(int)];
  112. #endif sun
  113. #ifdef sequent
  114.     _rtmp = (int) &private_stack[sizeof(private_stack) / sizeof(int)];
  115. #endif sequent
  116.  
  117. #ifdef mc68020
  118.     asm("movl sp, a0");
  119.     asm("movl __rtmp, sp");
  120.     asm("movl a0, __rtmp");
  121. #endif mc68020
  122. #ifdef    i386
  123.     asm("xchgl %esp, __rtmp");
  124. #endif    i386
  125. #ifdef    ns32000
  126.     asm("sprd sp, r0");
  127.     asm("lprd sp, __rtmp");
  128.     asm("movd r0, __rtmp");
  129. #endif    ns32000
  130.  
  131.     p_state = S_FORKING;
  132.  
  133.     pid = fork();
  134.     switch (pid)    {
  135.     case -1:    // fork error
  136. #ifdef mc68020
  137.         asm("movl __rtmp, sp");
  138. #endif mc68020
  139. #ifdef    i386
  140.         asm("movl __rtmp, %esp");
  141. #endif    i386
  142. #ifdef    ns32000
  143.         asm("lprd sp, __rtmp");
  144. #endif    ns32000
  145.         p_pid = -1;
  146.         return;    
  147.     case 0:        // child
  148.         p_ppid = getppid();
  149.         p_pid = getpid();
  150.         p_runchild(&spinonfork);
  151.         // NOTREACHED
  152.         error("Process forked child returned???");
  153.     default:    // parent: can't return until child finished with stack
  154. #ifdef mc68020
  155.         asm("movl __rtmp, sp");
  156. #endif mc68020
  157. #ifdef    i386
  158.         asm("movl __rtmp, %esp");
  159. #endif    i386
  160. #ifdef    ns32000
  161.         asm("lprd sp, __rtmp");
  162. #endif    ns32000
  163.         p_pid = pid;
  164.         while (spinonfork)
  165.             continue;
  166.     }
  167. }
  168.  
  169.  
  170. //
  171. // Fake being able to virtualize the constructor
  172. //
  173. Process*
  174. Process::newprocess(char* name, int id)
  175. {
  176.     return new Process(name, id);
  177. }
  178.  
  179.  
  180. //
  181. // Run the child scheduler.  Hold onto the parent until we get all
  182. // that we need from the args (this especially).  See comments.
  183. //
  184. void
  185. Process::p_runchild(int *spinonfork)
  186. {
  187.     extern int _rtmp;
  188.  
  189.     Thread* t = thisthread->newthread(p_name, 0, DEFSTACKSIZ, 1); 
  190.                             // force a stack
  191.  
  192.  
  193.     thisthread = t;            //  get what we need from our parents
  194.     thisproc = this;        //  stack
  195.  
  196.     //
  197.     _rtmp = (int)(thisthread->stack()->top());
  198.     { 
  199. #ifdef vax
  200. //    asm("movl    __rtmp, sp");
  201. #endif
  202. #ifdef mc68020
  203.     asm("movl    __rtmp, sp");
  204. #endif mc68020
  205. #ifdef ns32000
  206.     asm("lprd    sp, __rtmp");
  207. #endif
  208. #ifdef    i386
  209.     asm("movl    __rtmp, %esp");
  210. #endif
  211.     }    
  212.     //
  213.     // should have secondary entry point into start to avoid the test
  214.     // for a scheduler.
  215.     //
  216.     //
  217.     thisthread->setflags(TF_SCHEDULER|TF_KEEPSTACK|TF_NONPREEMPTABLE);
  218.     thisthread->start(thisproc, (PFany)(thisproc->invoke));
  219.     thisthread->setproc(thisproc);
  220.  
  221.     thisproc->p_schedthread = thisthread;
  222.     *spinonfork = 0;        // Let him go...
  223.     //
  224.     // The parent has just returned using the frame that our
  225.     // fp references.  This means that we can never return beyond
  226.     // this routine, AND we can't reference any of the params
  227.     // passed to us on the stack  (use thisthread and thisproc from
  228.     // here on).
  229.     //
  230.     // Can't use run since it won't let us idle "thisthread" and run
  231.     // "thisthread" at the same time.
  232.     //
  233.     thisthread->isrunning();
  234.     thisthread->runrun();        // fall into p_wait
  235.     thisthread->isnotrunning();
  236.  
  237.     //
  238.     // fall out of p_wait on its return to here
  239.     //
  240.     delete thisproc;
  241.     //
  242.     // should never get here
  243.     //
  244.     error("PROCESS DESTRUCTOR RETURNED");
  245. }
  246.  
  247. //
  248. // ~Process:    kill a Process.
  249. //    If we are the process to be killed, then we mark ourselves as a 
  250. //    zombie and _exit()  (no destructors will be called).  If we are
  251. //    trying to destroy another process, then we mark it
  252. //    as S_EXITING and then ask the process to actually return.
  253. //    This will have it fall back into runrun and then into
  254. //    p_runchild, where we will get called to kill it running
  255. //    as the process which is being asked to die.
  256. //
  257. //    Doing it this way allow processes to perform whatever cleanup
  258. //    they feel like before actually disappearing.
  259. //
  260. //    If we are the root process, we just return quietly
  261. //    
  262. //
  263.  
  264. Process::~Process()
  265. {
  266.     extern void shfree(Process*);
  267.     extern void free(Process*);
  268.  
  269.  
  270.     if (/*this &&*/  ((this->p_state&S_EXITING) == 0))    {
  271.         int pid = p_pid;
  272.         if (this == thisproc)    {
  273.             this->p_state = S_ZOMBIE;
  274.             if (this->isroot())    {
  275.                 this = 0;
  276.                 return;
  277.             }
  278.             //
  279.             // Our stack frame is gonna be all screwed up here
  280.             // since we started off with the fp running
  281.             // on our parent's frame, and he has now return.
  282.             // We can never return from this routine.
  283.             //
  284.             _exit(0);
  285.         } else    {
  286.             this->p_state = S_EXITING;
  287.             this->request(R_RETURN);
  288.         }
  289.     }
  290.     this = 0;
  291. }
  292.  
  293. int
  294. Process::invoke()
  295. {
  296.     p_wait();
  297.     return 0;
  298. }
  299.  
  300. //
  301. // Parent (or sibling) wakes up a looping Process here with the
  302. // "special" request code
  303. //
  304. int
  305. Process::request(int req)        
  306. {
  307.  
  308.     //
  309.     // If someone is stupid enough to make a request on a proc that
  310.     // is already servicing someone else... then they are just
  311.     // gonna have to wait their turn!
  312.     //
  313.     while (p_request != R_NULL)    {
  314.         if (p_request&(R_DIE|R_RETURN))    // no way to satisfy
  315.             return -1;
  316.     }
  317.  
  318.     p_request = req;
  319. #ifdef TDEBUG    
  320.     cerr << thisproc->name() << "making request " << req <<
  321.             " on " << this->name() << "\n";
  322. #endif        
  323.  
  324.     if (p_state&S_OSPAUSE)    {    // sleeping in os
  325.         cerr << "\nWaking up " << this << "\n";
  326.         return (kill(p_pid, SIGCONT));
  327.     } else        
  328.         return 0;
  329. }
  330.  
  331.  
  332. //
  333. // p_wait:    hang around and wait for something interesting
  334. //        to happen. That is, loop until someone bangs
  335. //        on our door, or until there is a readythread to
  336. //        start working on, OR we are not the root process, but our
  337. //        parent process seems to have disappeared (in which case
  338. //        we abort the scheduler, killing ourselves and all our 
  339. //        siblings).  We only check the last case "every so often" when 
  340. //        can't find anything else to do.
  341. //        This is an example of a "heuristic."  AI in action!
  342. //
  343. //        This doesn't guarantee that the system will always stop.  If
  344. //        the parent dies of as the result of an uncaught signal while
  345. //        holding a spinlock, the rest of the system could be blocked.
  346. //        If all other process are blocked, then the system will
  347. //        spin forever waiting for the holding process to relase
  348. //        the spinlock (which will never happend).  Lesson:
  349. //            Don't kill -9 the root process.
  350. //
  351. void
  352. Process::p_wait()
  353. {
  354.     int idlespan = 0;    
  355.     for (;;)    {
  356.         p_state = S_WAIT;
  357.         // wait until readythread, or until we get asynch request
  358.         if ( (p_request == NULL) && (p_thread = sched->getreadythread()) == NULL)    {
  359.              if (idlespan++ == 50000)    {
  360.                  // check if our parent has died and we are not root
  361.             if (!isroot() && getppid() != this->ppid())    {
  362.                 // kill myself and all siblings
  363.                 sched->abort(-SIGKILL);
  364.             } else    
  365.                 idlespan = 0;
  366.              }
  367.              continue;
  368.         }
  369.  
  370.         if (p_request)    {
  371.             //
  372.             // assumption is that only one thread can be diddling
  373.             // with processes at a time... otherwise this might
  374.             // not work.
  375.             //
  376.  
  377.             if (p_request & R_RETURN)    {
  378. //                if ( (p_flags&P_ROOT) == 0)
  379. //                    error("PROCS CANT RETURN YET\n");
  380. //                else
  381.                     return;
  382.             }
  383.  
  384.             //
  385.             // They can only die
  386.             //
  387.             if (p_request & R_DIE)        {    
  388.                 delete this;
  389.                 // not reached! 
  390.             }
  391.  
  392.             if (p_request & R_PARK)    {
  393.                 this->p_pause();
  394.                 continue;
  395.             };
  396.         } else    {        // must have a readythread
  397.             if (p_thread->flags()&TF_SCHEDULER)    {    
  398.                 p_thread->error("Can't schedule a scheduling thread");
  399.                 continue;        // NOT REACHED?
  400.             }
  401.             p_state = S_RUN;
  402.             (void)p_thread->run();    
  403.         }
  404.         // others
  405.     }
  406. }    
  407.  
  408.  
  409. //
  410. // p_pause:    internal version of park
  411. //
  412. void
  413. Process::p_pause()
  414. {
  415.     if (p_state != S_WAIT)    
  416.         error("p_pause called to pause non spinning process");
  417.  
  418.     p_state = S_OSPAUSE;
  419.     p_request = 0;        // must clear here, not above
  420.     ::pause();
  421.     p_state = S_WAIT;
  422. }
  423.  
  424. //
  425. // park:    Give it a rest buddy boy
  426. //
  427. void
  428. Process::park()
  429. {
  430.     if (this == thisproc)    {
  431.         cerr << "Warning: putting myself to sleep\n";
  432.         this->p_pause();
  433.     }
  434.     else    {
  435.         // baby you can drive my car
  436.         p_request = R_WAKEUP|R_PARK;
  437.     }
  438. }
  439.  
  440. void
  441. Process::drive()
  442. {
  443.     if (this == thisproc)
  444.         return;
  445.     else    {
  446.         if (p_state != S_OSPAUSE)
  447.             cerr << "Warning: proc not parked\n";
  448.         ::kill(p_pid, SIGCONT);
  449.     }
  450. }
  451.  
  452.  
  453. void
  454. Process::error(char *s)
  455. {
  456.     cerr << "Process error " << s << "  " << this << "\n";
  457.     fatalerror();
  458. }
  459.  
  460. // signal handler
  461. int p_continue()
  462. {
  463.     return 0;
  464. }
  465.  
  466.  
  467. void
  468. Process::print(ostream& s)
  469. {
  470.     s << form("(Process)=0x%x, p_id=%d, p_name=%s, p_pid=%d, p_ppid=%d, p_state=0x%x, p_request=%d",this,p_id,p_name,p_pid,p_ppid,p_state,p_request);
  471. }
  472.